summaryrefslogtreecommitdiff
path: root/app/[lng]/test/table-v2/columns.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'app/[lng]/test/table-v2/columns.tsx')
-rw-r--r--app/[lng]/test/table-v2/columns.tsx212
1 files changed, 212 insertions, 0 deletions
diff --git a/app/[lng]/test/table-v2/columns.tsx b/app/[lng]/test/table-v2/columns.tsx
new file mode 100644
index 00000000..703e9fd8
--- /dev/null
+++ b/app/[lng]/test/table-v2/columns.tsx
@@ -0,0 +1,212 @@
+"use client";
+
+import { ColumnDef } from "@tanstack/react-table";
+import { Badge } from "@/components/ui/badge";
+import { TestProduct } from "@/db/schema/test-table-v2";
+import { OrderWithDetails } from "./column-defs";
+
+// === Product Columns (Pattern 1, 2) ===
+// meta.serverGroupable: 서버 사이드 GROUP BY 지원 여부
+
+export const productColumns: ColumnDef<TestProduct>[] = [
+ {
+ accessorKey: "id",
+ header: "ID",
+ size: 60,
+ enableGrouping: false, // 클라이언트 그룹핑도 비활성화
+ meta: { serverGroupable: false },
+ },
+ {
+ accessorKey: "sku",
+ header: "SKU",
+ size: 100,
+ enableGrouping: false,
+ meta: { serverGroupable: false },
+ },
+ {
+ accessorKey: "name",
+ header: "Product Name",
+ size: 200,
+ enableGrouping: false,
+ meta: { serverGroupable: false },
+ },
+ {
+ accessorKey: "category",
+ header: "Category",
+ size: 120,
+ enableGrouping: true, // ✅ 그룹핑 가능
+ meta: { serverGroupable: true },
+ cell: ({ getValue }) => {
+ const category = getValue() as string;
+ return <Badge variant="outline">{category}</Badge>;
+ },
+ },
+ {
+ accessorKey: "price",
+ header: "Price",
+ size: 100,
+ enableGrouping: false,
+ meta: { serverGroupable: false },
+ cell: ({ getValue }) => {
+ const price = parseFloat(getValue() as string);
+ return new Intl.NumberFormat("en-US", {
+ style: "currency",
+ currency: "USD",
+ }).format(price);
+ },
+ },
+ {
+ accessorKey: "stock",
+ header: "Stock",
+ size: 80,
+ enableGrouping: false,
+ meta: { serverGroupable: false },
+ cell: ({ getValue }) => {
+ const stock = getValue() as number;
+ return (
+ <span className={stock < 10 ? "text-red-500 font-medium" : ""}>
+ {stock}
+ </span>
+ );
+ },
+ },
+ {
+ accessorKey: "status",
+ header: "Status",
+ size: 110,
+ enableGrouping: true, // ✅ 그룹핑 가능
+ meta: { serverGroupable: true },
+ cell: ({ getValue }) => {
+ const status = getValue() as string;
+ const variants: Record<string, "default" | "secondary" | "destructive"> = {
+ active: "default",
+ inactive: "secondary",
+ discontinued: "destructive",
+ };
+ return <Badge variant={variants[status] || "secondary"}>{status}</Badge>;
+ },
+ },
+ {
+ accessorKey: "isNew",
+ header: "New",
+ size: 60,
+ enableGrouping: true, // ✅ 그룹핑 가능
+ meta: { serverGroupable: true },
+ cell: ({ getValue }) => {
+ const isNew = getValue() as boolean;
+ return isNew ? <Badge className="bg-emerald-500">NEW</Badge> : null;
+ },
+ },
+ {
+ accessorKey: "createdAt",
+ header: "Created",
+ size: 110,
+ enableGrouping: false,
+ meta: { serverGroupable: false },
+ cell: ({ getValue }) => {
+ const date = getValue() as Date;
+ return date ? new Date(date).toLocaleDateString() : "-";
+ },
+ },
+];
+
+// === Order Columns with joined data (Pattern 3 - Custom Service) ===
+
+export const orderColumns: ColumnDef<OrderWithDetails>[] = [
+ {
+ accessorKey: "id",
+ header: "ID",
+ size: 60,
+ },
+ {
+ accessorKey: "orderNumber",
+ header: "Order #",
+ size: 140,
+ cell: ({ getValue }) => (
+ <span className="font-mono text-xs">{getValue() as string}</span>
+ ),
+ },
+ {
+ accessorKey: "customerName",
+ header: "Customer",
+ size: 150,
+ },
+ {
+ accessorKey: "customerTier",
+ header: "Tier",
+ size: 90,
+ cell: ({ getValue }) => {
+ const tier = getValue() as string;
+ if (!tier) return "-";
+ const colors: Record<string, string> = {
+ standard: "bg-gray-500",
+ premium: "bg-blue-500",
+ vip: "bg-amber-500",
+ };
+ return (
+ <Badge className={colors[tier] || "bg-gray-500"}>
+ {tier.toUpperCase()}
+ </Badge>
+ );
+ },
+ },
+ {
+ accessorKey: "productName",
+ header: "Product",
+ size: 180,
+ },
+ {
+ accessorKey: "quantity",
+ header: "Qty",
+ size: 60,
+ },
+ {
+ accessorKey: "totalAmount",
+ header: "Total",
+ size: 100,
+ cell: ({ getValue }) => {
+ const amount = parseFloat(getValue() as string);
+ return new Intl.NumberFormat("en-US", {
+ style: "currency",
+ currency: "USD",
+ }).format(amount);
+ },
+ },
+ {
+ accessorKey: "status",
+ header: "Status",
+ size: 110,
+ cell: ({ getValue }) => {
+ const status = getValue() as string;
+ const variants: Record<string, "default" | "secondary" | "destructive" | "outline"> = {
+ pending: "outline",
+ processing: "secondary",
+ shipped: "default",
+ delivered: "default",
+ cancelled: "destructive",
+ };
+ const colors: Record<string, string> = {
+ delivered: "bg-emerald-500",
+ shipped: "bg-blue-500",
+ };
+ return (
+ <Badge
+ variant={variants[status] || "secondary"}
+ className={colors[status] || ""}
+ >
+ {status}
+ </Badge>
+ );
+ },
+ },
+ {
+ accessorKey: "orderedAt",
+ header: "Order Date",
+ size: 110,
+ cell: ({ getValue }) => {
+ const date = getValue() as Date;
+ return date ? new Date(date).toLocaleDateString() : "-";
+ },
+ },
+];
+